From c0e4dc886eaba03485ea4aaac37eaffb311aeb74 Mon Sep 17 00:00:00 2001 From: Fuwn Date: Tue, 2 Jan 2024 21:47:28 -0800 Subject: feat(badges): categories --- src/routes/user/[user]/badges/+page.svelte | 102 +++++++++++++++++++++-------- 1 file changed, 74 insertions(+), 28 deletions(-) (limited to 'src/routes/user/[user]') diff --git a/src/routes/user/[user]/badges/+page.svelte b/src/routes/user/[user]/badges/+page.svelte index 20d4775a..69965e83 100644 --- a/src/routes/user/[user]/badges/+page.svelte +++ b/src/routes/user/[user]/badges/+page.svelte @@ -21,6 +21,8 @@ let confirmDelete = 0; let selectedBadge: Badge | undefined = undefined; + type GroupedBadges = { [key: string]: Badge[] }; + onMount(async () => { // socket.on('badges', (message) => (badges = message)); @@ -45,6 +47,7 @@ const activityURL = document.querySelector('input[name="activity_url"]') as HTMLInputElement; const description = document.querySelector('input[name="description"]') as HTMLInputElement; const time = document.querySelector('input[type="datetime-local"]') as HTMLInputElement; + const category = document.querySelector('input[name="category"]') as HTMLInputElement; if (!imageURL.value) { error = 'Image URL cannot be empty.'; @@ -66,7 +69,7 @@ activityURL.value || '#' )}${ description.value.length > 0 ? `&description=${encodeURIComponent(description.value)}` : '' - }${ + }${category.value.length > 0 ? `&category=${encodeURIComponent(category.value)}` : ''}${ time.valueAsDate ? `&time=${encodeURIComponent(dateToDatabaseTime(time.valueAsDate))}` : '' }${ selectedBadge && selectedBadge.id ? `&update=${encodeURIComponent(selectedBadge.id)}` : '' @@ -163,6 +166,26 @@ element.classList.remove('invert'); } }; + + const groupBadges = (badges: Badge[]) => { + const groupedBadges: GroupedBadges = {}; + + badges.forEach((badge) => { + if (!badge.category) badge.category = 'Uncategorized'; + + if (!groupedBadges[badge.category]) groupedBadges[badge.category] = []; + + groupedBadges[badge.category].push(badge); + }); + + return Object.entries(groupedBadges) + .sort((a, b) => b[1].length - a[1].length) + .reduce((set: GroupedBadges, [key, value]) => { + set[key] = value; + + return set; + }, {}); + }; @@ -227,6 +250,15 @@ size="11" value={selectedBadge ? selectedBadge.description : ''} /> + {selectedBadge ? 'Update' : 'Add'} Badge {#if selectedBadge} or @@ -253,36 +285,50 @@ {#if badgesResponse} {#await badgesResponse.json()} Loading badges ... 80% - {:then badges} + {:then ungroupedBadges}
- {#if badges === null} + {#if ungroupedBadges === null} {@html nbsp('Loading badges ... 50%')} - {:else if badges.length === 0} + {:else if ungroupedBadges.length === 0} {@html nbsp('No badges found for this user.')} {:else} - {#each badges as badge} - {#if editMode} - (selectedBadge = badge)} - id={`badge-${badge.id}`} - title={`${databaseTimeToDate(badge.time).toLocaleString()}${ - badge.description ? `\n${badge.description}` : '' - }`} - > - {badge.description} - - {:else} - - {badge.description} - + {@const groupedBadges = Object.entries(groupBadges(ungroupedBadges))} + + {#each groupedBadges as [category, badges]} +
+ {category} + + +
+ + {#if groupedBadges[groupedBadges.length - 1][0] !== category} +

{/if} {/each} {/if} @@ -311,7 +357,7 @@ height: auto; } - #badges { + .badges { display: grid; grid-template-columns: repeat(auto-fill, minmax(8%, 1fr)); grid-gap: 0.25%; -- cgit v1.2.3